package com.vhall.component.service.pendant.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.pendant.PendantMapper;
import com.vhall.component.dao.pendant.PendantMappingMapper;
import com.vhall.component.dao.pendant.PendantStatsMapper;
import com.vhall.component.dao.room.RoomMapper;
import com.vhall.component.entity.page.vo.PageVO;
import com.vhall.component.entity.pendant.PendantEntity;
import com.vhall.component.entity.pendant.PendantMappingEntity;
import com.vhall.component.entity.pendant.vo.*;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.entity.room.entity.RoomsEntity;
import com.vhall.component.entity.room.enums.RoomAuditStatusEnum;
import com.vhall.component.entity.room.enums.RoomStatusEnum;
import com.vhall.component.entity.subject.enums.StatusEnum;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.enums.DeleteStatusEnum;
import com.vhall.component.plugin.common.enums.RoomConfigStatusEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.BeanCopyUtil;
import com.vhall.component.service.account.BaseUserPermissionService;
import com.vhall.component.service.common.BaseCommonService;
import com.vhall.component.service.pendant.PendantConsoleService;
import com.vhall.component.service.pendant.common.PendantConstant;
import com.vhall.component.service.room.RoomInnerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Preconditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author guoxin.wang
 * @date 2021-10-29
 */
@Slf4j
@Service
public class PendantConsoleServiceImpl extends BaseUserPermissionService implements PendantConsoleService {

    @Autowired
    private PendantMapper pendantMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RoomInnerService roomInnerService;

    @Autowired
    private PendantStatsMapper pendantStatsMapper;

    @Autowired
    private PendantMappingMapper pendantMappingMapper;

    @Autowired
    private RoomMapper roomMapper;

    @Resource
    private BaseCommonService baseCommonService;

    @Override
    public Boolean create(PendantCreateOrUpdateReqVO reqVO) {


        // 类型转换
        PendantEntity to = new PendantEntity();
        BeanCopyUtil.copy(reqVO, to);

        to.setCreatedAt(LocalDateTime.now());
        addUserInfo(to);

        return pendantMapper.insert(to) > 0;
    }

    @Override
    public Boolean delete(PendantDeleteReqVO reqVO) {


        Set<String> ids = reqVO.getIds();

        // 基础校验
        List<Integer> idsList = new ArrayList<>();
        for (String id : ids) {
            idsList.add(Integer.valueOf(id));
        }
        basicValidate(idsList);

        // 执行软删除
        LambdaUpdateWrapper<PendantEntity> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.in(PendantEntity::getId, ids)
                .eq(PendantEntity::getStatus, PendantConstant.STATUS_ON)
                .eq(StringUtils.isNotBlank(getUserPermission()), PendantEntity::getOrgCode, getUserPermission());

        updateWrapper.set(PendantEntity::getStatus, PendantConstant.STATUS_OFF)
                .set(PendantEntity::getUpdatedAt, LocalDateTime.now());
        int updCount = pendantMapper.update(null, updateWrapper);
        if (updCount <= 0) {
            throw new BusinessException(BizErrorCode.COMP_PENDANT_ERROR);
        }
        return true;
    }

    @Override
    public Boolean edit(PendantCreateOrUpdateReqVO reqVO) {
        Preconditions.checkArgument(reqVO.getId() != null, "id不能为空！");


        // 基础校验
        basicValidate(Collections.singletonList(reqVO.getId()));

        // 查询数据是否存在
        LambdaQueryWrapper<PendantEntity> query = Wrappers.lambdaQuery();
        query.eq(PendantEntity::getId, reqVO.getId())
                .eq(PendantEntity::getStatus, PendantConstant.STATUS_ON)
                .eq(StringUtils.isNotBlank(getUserPermission()), PendantEntity::getOrgCode, getUserPermission());

        PendantEntity updPendant = new PendantEntity();
        BeanCopyUtil.copy(reqVO, updPendant);
        if (StringUtils.isNotBlank(getUserPermission())) {
            updPendant.setOrgCode(getUserPermission());
        }
        updPendant.setUpdatedAt(LocalDateTime.now());
        updPendant.setId(reqVO.getId());

        int updCount = pendantMapper.updateInfo(updPendant);
        if (updCount <= 0) {
            query.clear();
            // 若修改不到数据，去掉创建人条件查询一次，若能查到，则代表无权限修改
            query.eq(PendantEntity::getId, reqVO.getId()).eq(PendantEntity::getStatus, PendantConstant.STATUS_ON);
            if (pendantMapper.selectCount(query) > 0) {
                throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
            }
            throw new BusinessException(BizErrorCode.COMP_PENDANT_EMPTY);
        }
        return true;
    }

    /**
     * 判断当前挂件是否已经绑定，绑定不允许修改
     */
    private void basicValidate(List<Integer> ids) {
        // 判断当前挂件是否已经绑定，绑定不允许修改
        LambdaQueryWrapper<PendantMappingEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(PendantMappingEntity::getPendantId, ids);
        queryWrapper.eq(PendantMappingEntity::getDeleted, DeleteStatusEnum.NO_DELETE.getStatus());
        List<PendantMappingEntity> pendantMappingEntities = pendantMappingMapper.selectList(queryWrapper);

        if (CollectionUtil.isEmpty(pendantMappingEntities)) {
            return;
        }

        List<String> list = pendantMappingEntities.stream().map(PendantMappingEntity::getRoomId).collect(Collectors.toList());
        LambdaQueryWrapper<RoomsEntity> RoomsEntityWrapper = Wrappers.lambdaQuery();
        RoomsEntityWrapper.in(RoomsEntity::getRoomId, list);
        List<RoomsEntity> roomsEntities = roomMapper.selectList(RoomsEntityWrapper);

        if (CollectionUtil.isNotEmpty(roomsEntities)) {
            throw new BusinessException(MessageFormat.format("挂件已使用，请先解除房间：{0}绑定", roomsEntities.stream().map(RoomsEntity::getIlId).collect(Collectors.toList()).toString()));
        }

    }

    @Override
    public PageVO<PendantRspVO> list(PendantListReqVO reqVO) {
        reqVO.setDefault();

        // 进行查询
        LambdaQueryWrapper<PendantEntity> where = Wrappers.lambdaQuery();
        where.eq(StringUtils.isNotBlank(getUserPermission()), PendantEntity::getOrgCode, getUserPermission());
        where.eq(reqVO.getType() != null, PendantEntity::getType, reqVO.getType());
        where.eq(PendantEntity::getStatus, PendantConstant.STATUS_ON);
        where.and(StringUtils.isNotEmpty(reqVO.getKeyword()),
                w -> w.like(PendantEntity::getName, reqVO.getKeyword()));
        where.orderByDesc(PendantEntity::getId);
        Page<PendantEntity> page = new Page<>(reqVO.getPage(), reqVO.getPageSize());
        page = pendantMapper.selectPage(page, where);
        List<PendantRspVO> list = BeanCopyUtil.batchCopy(page.getRecords(), PendantRspVO::new);
        if(CollectionUtil.isNotEmpty(list)){
            for (PendantRspVO pendantRspVO : list) {
                baseCommonService.convertUrl(pendantRspVO, "pic");
            }
        }
        return new PageVO<>(reqVO.getPage(), reqVO.getPageSize(), (int) page.getTotal(), list);
    }

    /**
     * 分为两种情况，取消默认。设置默认。
     */
    @Override
    public Boolean setDefaultFixed(PendantSetDefaultReqVO reqVO) {
        // 根据token获取用户信息
        Token accountInfo = TokenThreadLocal.getToken();
        LocalDateTime now = LocalDateTime.now();
        Integer isDefault = reqVO.getIsDefault();
        if (Objects.isNull(isDefault) || !Arrays.asList(PendantConstant.DEFAULT_ON, PendantConstant.DEFAULT_OFF)
                .contains(isDefault)) {
            log.error("【控制台-设置默认固定挂件】is_default参数无效，is_default={}", isDefault);
            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
        }
        LambdaUpdateWrapper<PendantEntity> updateWrapper = Wrappers.lambdaUpdate();
        if (PendantConstant.DEFAULT_OFF.equals(reqVO.getIsDefault())) {
            // 1、取消默认的话，直接更新处理
            updateWrapper.eq(PendantEntity::getId, reqVO.getId()).eq(PendantEntity::getStatus, PendantConstant.STATUS_ON);
            updateWrapper.set(PendantEntity::getIsDefault, reqVO.getIsDefault());
            updateWrapper.set(PendantEntity::getUpdatedAt, now);
            pendantMapper.update(null, updateWrapper);


            //设置账号级挂机开关
            roomInnerService.insertOrUpdateRoomConfigByAccountId(accountInfo.getAccountId(), StatusEnum.CLOSE.getValue(), RoomConfigStatusEnum.PENDANT_STATUS.getValue());
        } else if (PendantConstant.DEFAULT_ON.equals(reqVO.getIsDefault())) {
            // 取消已设置的固定挂件
            updateWrapper.eq(PendantEntity::getAccountId, accountInfo.getAccountId())
                    .eq(PendantEntity::getStatus, PendantConstant.STATUS_ON)
                    .eq(PendantEntity::getIsDefault, PendantConstant.DEFAULT_ON);
            updateWrapper.set(PendantEntity::getIsDefault, PendantConstant.DEFAULT_OFF).set(PendantEntity::getUpdatedAt, now);
            pendantMapper.update(null, updateWrapper);
            updateWrapper.clear();
            // 设置对应挂件为默认固定挂件
            updateWrapper.eq(PendantEntity::getId, reqVO.getId()).eq(PendantEntity::getStatus, PendantConstant.STATUS_ON)
                    .eq(PendantEntity::getIsDefault, PendantConstant.DEFAULT_OFF);
            updateWrapper.set(PendantEntity::getIsDefault, PendantConstant.DEFAULT_ON).set(PendantEntity::getUpdatedAt, now);
            pendantMapper.update(null, updateWrapper);

            //设置账号级挂机开关
            roomInnerService.insertOrUpdateRoomConfigByAccountId(accountInfo.getAccountId(), StatusEnum.OPEN.getValue(), RoomConfigStatusEnum.PENDANT_STATUS.getValue());
        }
        return true;
    }


    @Override
    public PageVO<PendantListStatsRspVO> listStats(PendantListStatsReqVO reqVO) {
        reqVO.setDefault();
        PageVO<PendantListStatsRspVO> result;
        // 获取房间信息。
        RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(reqVO.getRoomId());
        if (roomInfo == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        Page<PendantListStatsRspVO> page = new Page<>(reqVO.getPage(), reqVO.getPageSize());
        Map<String, Object> param = new HashMap<>(4);
        param.put("ilId", roomInfo.getIlId());
        param.put("pendantType", reqVO.getType());
        param.put("beginTime", reqVO.getStartTime());
        param.put("endTime", reqVO.getEndTime());
        page = pendantStatsMapper.listStats(page, param);
        result = new PageVO<>(reqVO.getPage(), reqVO.getPageSize(), (int) page.getTotal(), page.getRecords());
        return result;
    }

    /**
     * 获取该账号下默认固定挂件信息。
     */
    @Override
    public PendantEntity getDefaultFixed(RoomsEntityDTO roomInfo) {

        PendantEntity result = new PendantEntity();
        // 从缓存获取，如果缓存中不存在，从数据库中查询并放入缓存中。
        String key = PendantConstant.PENDANT_FIXED_INFO_KEY + roomInfo.getRoomId();
        String s = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(s)) {
            // 从数据库中查询。
            List<PendantEntity> pendantEntities = pendantMappingMapper.bindingList(PendantListReqVO.builder().roomId(roomInfo.getRoomId()).build());
            if (CollectionUtil.isNotEmpty(pendantEntities)) {
                List<PendantEntity> entityList = pendantEntities.stream().filter(e -> e.getType().equals(PendantConstant.TYPE_FIXED)).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(entityList)) {
                    result = entityList.get(0);
                    stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(result));
                }
            }
        } else {
            result = JSON.parseObject(s, PendantEntity.class);
        }
        return result;
    }

    @Override
    public List<PendantRspVO> bindingList(PendantListReqVO reqVO) {
        Preconditions.checkArgument(StringUtils.isNotBlank(reqVO.getRoomId()), "房间号不能为空！");
        List<PendantEntity> pendantEntities = pendantMappingMapper.bindingList(reqVO);
        if (CollectionUtil.isEmpty(pendantEntities)) {
            return new ArrayList<>();
        }
        List<PendantRspVO> pendantRspVOS = BeanCopyUtil.batchCopy(pendantEntities, PendantRspVO::new);
        for (PendantRspVO pendantRspVO : pendantRspVOS) {
            baseCommonService.convertUrl(pendantRspVO, "pic");
        }
        return pendantRspVOS;

    }

    @Override
    public PageVO<PendantRspVO> unbindingList(PendantListReqVO reqVO) {

        Preconditions.checkArgument(StringUtils.isNotBlank(reqVO.getRoomId()), "房间号不能为空！");
        List<PendantEntity> pendantEntities = pendantMappingMapper.bindingList(reqVO);
        List<Integer> bindingIdList = null;
        if (CollectionUtil.isNotEmpty(pendantEntities)) {
            bindingIdList = pendantEntities.stream().map(PendantEntity::getId).collect(Collectors.toList());
        }

        Page<PendantEntity> page = new Page<>(reqVO.getPage(), reqVO.getPageSize());
        LambdaQueryWrapper<PendantEntity> where = Wrappers.lambdaQuery();
        where.notIn(CollectionUtil.isNotEmpty(bindingIdList), PendantEntity::getId, bindingIdList);
        where.eq(PendantEntity::getStatus, 1);
        where.eq(StringUtils.isNotBlank(getUserPermission()), PendantEntity::getOrgCode, getUserPermission());
        where.eq(reqVO.getType() != null, PendantEntity::getType, reqVO.getType());
        where.and(StringUtils.isNotBlank(reqVO.getKeyword()), wq -> wq.eq(PendantEntity::getId, reqVO.getKeyword()).or().like(PendantEntity::getName, reqVO.getKeyword()));


        where.orderByDesc(PendantEntity::getId);

        page = pendantMapper.selectPage(page, where);

        List<PendantRspVO> vos = CollectionUtil.isEmpty(page.getRecords()) ? new ArrayList<>() : BeanCopyUtil.batchCopy(page.getRecords(), PendantRspVO::new);

        if(CollectionUtil.isNotEmpty(vos)){
            for (PendantRspVO pendantRspVO : vos) {
                baseCommonService.convertUrl(pendantRspVO, "pic");
            }
        }

        return new PageVO<>(reqVO.getPage(), reqVO.getPageSize(), (int) page.getTotal(), vos);

    }

    @Override
    public Boolean bindingOperation(BindingOperationReqVO reqVO) {
        int operationType = reqVO.getOperationType();
        List<Integer> ids = reqVO.getIds();
        Preconditions.checkArgument(CollectionUtil.isNotEmpty(ids), "关联挂件不能为空！");

        LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomsEntity::getRoomId, reqVO.getRoomId());
        RoomsEntity roomsEntity = roomMapper.selectOne(wrapper);
        Preconditions.checkArgument(!roomsEntity.getStatus().equals(RoomStatusEnum.LIVE_BROADCAST.getStatus()), "当前房间不能操作挂件！");

        if (operationType == 0) {
            Preconditions.checkArgument(ids.size() <= 10, "关联挂件不能超过10个！");

            // 绑定
            LambdaQueryWrapper<PendantMappingEntity> query = Wrappers.lambdaQuery();
            query.in(PendantMappingEntity::getPendantId, ids);
            query.eq(PendantMappingEntity::getRoomId, reqVO.getRoomId());
            query.eq(PendantMappingEntity::getDeleted, DeleteStatusEnum.NO_DELETE.getStatus());
            List<PendantMappingEntity> pendantMappingEntities = pendantMappingMapper.selectList(query);
            Preconditions.checkArgument(CollectionUtil.isEmpty(pendantMappingEntities), "挂件已经被关联，请勿重复操作！");

            LambdaQueryWrapper<PendantMappingEntity> query2 = Wrappers.lambdaQuery();
            query2.eq(PendantMappingEntity::getRoomId, reqVO.getRoomId());
            query2.eq(PendantMappingEntity::getDeleted, DeleteStatusEnum.NO_DELETE.getStatus());
            List<PendantMappingEntity> pendantMappingEntities1 = pendantMappingMapper.selectList(query2);
            Preconditions.checkArgument((CollectionUtil.isEmpty(pendantMappingEntities1) ? 0 : pendantMappingEntities1.size()) + ids.size() <= 10, "关联挂件不能超过10个！");

            List<Integer> havebindingIds = pendantMappingEntities1.stream().map(PendantMappingEntity::getPendantId).collect(Collectors.toList());
            List<Integer> queryIds = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(havebindingIds)) {
                queryIds.addAll(havebindingIds);
            }
            queryIds.addAll(ids);

            List<PendantEntity> pendantEntities = pendantMapper.selectBatchIds(queryIds);
            int size = (int) pendantEntities.stream().filter(e -> e.getType().equals(2)).count();
            Preconditions.checkArgument(size <= 1, "固定挂件不能超过1个！");


            for (Integer id : ids) {
                PendantMappingEntity pendantMappingEntity = new PendantMappingEntity();
                pendantMappingEntity.setRoomId(reqVO.getRoomId());
                pendantMappingEntity.setPendantId(id);
                addUserInfo(pendantMappingEntity);
                pendantMappingMapper.insert(pendantMappingEntity);
            }

            roomInnerService.updateConfigValueByRoomId(reqVO.getRoomId(), StatusEnum.OPEN.getValue(), RoomConfigStatusEnum.PENDANT_STATUS.getValue());

        } else {
            LambdaUpdateWrapper<PendantMappingEntity> where = Wrappers.lambdaUpdate();
            where.set(PendantMappingEntity::getDeleted, DeleteStatusEnum.DELETE.getStatus())
                    .set(PendantMappingEntity::getUpdatedAt, LocalDateTime.now())

                    .eq(PendantMappingEntity::getDeleted, DeleteStatusEnum.NO_DELETE.getStatus())
                    .eq(PendantMappingEntity::getRoomId, reqVO.getRoomId())
                    .in(PendantMappingEntity::getPendantId, reqVO.getIds());
            pendantMappingMapper.update(null, where);

        }

        // 删除挂件缓存
        String key = PendantConstant.PENDANT_FIXED_INFO_KEY + reqVO.getRoomId();
        stringRedisTemplate.delete(key);

        //只有正式直播才做状态重置
        // 绑定成功之后，当前房间状态改为送审，需要点击【送审】按钮进行审核
        if (Objects.equals(roomsEntity.getLiveRormal(),1)) {
            roomInnerService.updateByIl(RoomsEntityDTO.builder()
                    .auditStatus(RoomAuditStatusEnum.SUBMIT_FOR_APPROVAL.getAuditStatus())
                            .auditNote("")
                    .updatedAt(LocalDateTime.now())
                    .roomId(reqVO.getRoomId()).build());
        }



        return true;
    }


}
